typeid 1.0.2

Const TypeId and non-'static TypeId
Documentation

Const TypeId and non-'static TypeId

Const TypeId

This crate provides ConstTypeId, which is like core::any::TypeId but is constructible in const in stable Rust. (The standard library's TypeId's is nightly-only to construct in const; the tracking issue for this is rust#77125.)

Being able to construct ConstTypeId in const makes it suitable for use cases that rely on static promotion:

use std::fmt::{self, Debug, Display};
use std::ptr;
use typeid::ConstTypeId;

pub struct ObjectVTable {
    type_id: ConstTypeId,
    drop_in_place: unsafe fn(*mut ()),
    display: unsafe fn(*const (), &mut fmt::Formatter) -> fmt::Result,
    debug: unsafe fn(*const (), &mut fmt::Formatter) -> fmt::Result,
}

impl ObjectVTable {
    pub const fn new<T: Display + Debug>() -> &'static Self {
        &ObjectVTable {
            type_id: const { ConstTypeId::of::<T>() },
            drop_in_place: |ptr| unsafe { ptr::drop_in_place(ptr.cast::<T>()) },
            display: |ptr, f| unsafe { Display::fmt(&*ptr.cast::<T>(), f) },
            debug: |ptr, f| unsafe { Debug::fmt(&*ptr.cast::<T>(), f) },
        }
    }
}

and in associated constants:

use typeid::ConstTypeId;

pub trait GetTypeId {
    const TYPEID: ConstTypeId;
}

impl<T: 'static> GetTypeId for T {
    const TYPEID: ConstTypeId = ConstTypeId::of::<Self>();
}

Non-'static TypeId

This crate provides typeid::of, which takes an arbitrary non-'static type T and produces the TypeId for the type obtained by replacing all lifetimes in T by 'static, other than higher-rank lifetimes found in trait objects.

For example if T is &'b dyn for<'a> Trait<'a, 'c>, then typeid::of::<T>() produces the TypeId of &'static dyn for<'a> Trait<'a, 'static>.

It should be obvious that unlike with the standard library's TypeId, typeid::of::<A>() == typeid::of::<B>() does not mean that A and B are the same type. However, there is a common special case where this behavior is exactly what is needed. If:

  • A is an arbitrary non-'static type parameter, and
  • B is 'static, and
  • all types with the same id as B are also 'static

then typeid::of::<A>() == typeid::of::<B>() guarantees that A and B are the same type.

use core::any::TypeId;
use core::slice;

pub fn example<T>(slice: &[T]) {
    // T is arbitrary and non-'static.

    if typeid::of::<T>() == TypeId::of::<u8>() {
        // T is definitely u8
        let bytes = unsafe { slice::from_raw_parts(slice.as_ptr().cast(), slice.len()) };
        process_bytes(bytes);
    } else {
        for t in slice {
            process(t);
        }
    }
}

fn process<T>(_: &T) {/* ... */}
fn process_bytes(_: &[u8]) {/* ... */}

License